﻿#region Copyright(c) 2006 ZO, All right reserved.
// -----------------------------------------------------------------------------
// Copyright(c) 2006 ZO, All right reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
//   1.  Redistribution of source code must retain the above copyright notice,
//       this list of conditions and the following disclaimer.
//   2.  Redistribution in binary form must reproduce the above copyright
//       notice, this list of conditions and the following disclaimer in the
//       documentation and/or other materials provided with the distribution.
//   3.  The name of the author may not be used to endorse or promote products
//       derived from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
// EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
// OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
// ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// -----------------------------------------------------------------------------
#endregion


#region Using directives

using System;
using System.Diagnostics.CodeAnalysis;
using System.IO;
using System.IO.IsolatedStorage;
using System.Security;
using ZO.SmartCore.Collections.Generic;
using ZO.SmartCore.IO;
using ZO.SmartCore.Xml;
using ArgumentNullException= ZO.SmartCore.Core.ArgumentNullException;

#endregion

namespace ZO.SmartCore.Configuration
{
    /// <summary>
    /// read and write the <see cref="T:System.IO.MemoryStream"/> to the Isolated location on disk.
    /// </summary>
    public class IsolatedConfigurationProvider : IConfigurationProvider
    {

        #region Constructors

        #endregion

        #region Destructor

        #endregion

        #region Fields
        private IsolatedStorageScope _Scope = IsolatedStorageScope.Assembly;
        private object domainIdentity;

        private object assemblyIdentity;

        #endregion

        #region Events

        #endregion

        #region Operators

        #endregion

        #region Properties
        /// <summary>
        /// Gets or sets the scope of isolation.
        /// </summary>
        /// <value>The scope.</value>
        public IsolatedStorageScope Scope
        {
            get
            {
                return _Scope;
            }
            set
            {
                _Scope = value;
            }
        }

        /// <summary>
        /// Gets or sets the assembly identity.
        /// </summary>
        /// <value>The assembly identity.</value>
        public virtual object AssemblyIdentity
        {
            get
            {
                return this.assemblyIdentity;
            }
            set
            {
                this.assemblyIdentity = value;
            }
        }

        /// <summary>
        /// Gets or sets the domain identity.
        /// </summary>
        /// <value>The domain identity.</value>
        public virtual object DomainIdentity
        {
            get
            {
                return this.domainIdentity;
            }
            set
            {
                this.domainIdentity = value;
            }
        }
        #endregion

        #region Methods
        /// <summary>
        /// Gets the isolated storage.
        /// </summary>
        /// <returns></returns>
        [SuppressMessage("Microsoft.Design", "CA1024:UsePropertiesWhereAppropriate")]
        protected IsolatedStorageFile GetIsolatedStorage()
        {
            switch (this.Scope)
            {
                case IsolatedStorageScope.Domain:
                    return IsolatedStorageFile.GetUserStoreForDomain();

                case IsolatedStorageScope.Assembly:
                    return IsolatedStorageFile.GetUserStoreForAssembly();

                //doesn't work
                //return IsolatedStorageFile.GetStore(this.Scope, (domainIdentity == null) ? null: domainIdentity, (assemblyIdentity == null) ? null: assemblyIdentity);
            }
            if ((domainIdentity == null) && (assemblyIdentity == null))
            {
                return IsolatedStorageFile.GetStore(this.Scope, null, null);
            }
            if ((domainIdentity == null) && (assemblyIdentity != null))
            {
                return IsolatedStorageFile.GetStore(this.Scope, null, assemblyIdentity);
            }
            if ((domainIdentity != null) && (assemblyIdentity == null))
            {
                return IsolatedStorageFile.GetStore(this.Scope, domainIdentity, null);
            }
            return IsolatedStorageFile.GetStore(this.Scope, domainIdentity, assemblyIdentity);

        }
        #endregion

        #region IConfigurationProvider Members




        /// <summary>
        /// Gets the XML document from provider.
        /// </summary>
        /// <param name="file">The file.</param>
        /// <returns></returns>
        public virtual Document GetXmlDocument(string file)
        {
            StringStream data = this.Load(file);

            if (data != null && data.Length > 0)
            {
                Document xmlDoc = new Document();

                xmlDoc.LoadXml(data.ToString());

                return xmlDoc;
            }
            return null;
        }

        /// <summary>
        /// Saves the XML document in provider space.
        /// </summary>
        /// <param name="file">The file.</param>
        /// <param name="xmlDoc">The XML document to save.</param>
        public virtual void SaveXmlDocument(string file, Document xmlDoc)
        {
            if (xmlDoc != null)
            {
                this.Save(file, new StringStream(xmlDoc.ToString()));
            }
        }



        /// <summary>
        /// Get Whether specified file exists
        /// </summary>
        /// <param name="fileName">Name of the file.</param>
        /// <returns>true if file exists else false</returns>
        public virtual bool FileExists(string fileName)
        {
            if (String.IsNullOrEmpty(fileName))
            {
                return false;
            } // if

            using (IsolatedStorageFile isoStorage = this.GetIsolatedStorage())
            {
                string[] storeNames = isoStorage.GetFileNames(fileName);

                if (storeNames == null || storeNames.Length == 0)
                {
                    return false;
                } // if
                else
                {
                    foreach (string var in storeNames)
                    {
                        if (String.Compare(var, fileName, StringComparison.OrdinalIgnoreCase) == 0)
                        {
                            return true;
                        }
                    }
                }
            }

            return false;

        }


        /// <summary>
        /// Gets all the files names in specified folder.
        /// </summary>
        /// <param name="directoryName">Name of the directory.</param>
        /// <returns>All files name in specified folder</returns>
        public virtual string[] GetFilesNames(string directoryName)
        {
            List<string> list = new List<string>();

            if (String.IsNullOrEmpty(directoryName))
            {
                return list.ToArray();
            } // if

            using (IsolatedStorageFile isoStorage = this.GetIsolatedStorage())
            {
                string[] storeNames = isoStorage.GetDirectoryNames(directoryName);

                if (storeNames == null || storeNames.Length == 0)
                {
                    return list.ToArray();
                } // if
                else
                {
                    foreach (string var in storeNames)
                    {
                        if (String.Compare(var, directoryName, StringComparison.OrdinalIgnoreCase) == 0)
                        {
                            string[] fileNames = isoStorage.GetFileNames("*");

                            if (fileNames == null || fileNames.Length == 0)
                            {
                                return list.ToArray();
                            } // if
                            else
                            {
                                foreach (string var2 in fileNames)
                                {
                                    list.Add(var2);
                                }
                            }
                        }
                    }
                }
            };

            return list.ToArray();
        }


        /// <summary>
        /// Gets all the files names in specified folder.
        /// </summary>
        /// <param name="directoryName">Name of the directory.</param>
        /// <param name="searchPattern">The search string to match against the names of files in path.</param>
        /// <returns>All files name in specified folder</returns>
        public virtual string[] GetFilesNames(string directoryName, string searchPattern)
        {
            List<string> list = new List<string>();

            if (String.IsNullOrEmpty(directoryName))
            {
                return list.ToArray();
            } // if

            using (IsolatedStorageFile isoStorage = this.GetIsolatedStorage())
            {
                string[] storeNames = isoStorage.GetDirectoryNames(directoryName);

                if (storeNames == null || storeNames.Length == 0)
                {
                    return list.ToArray();
                } // if
                else
                {
                    foreach (string var in storeNames)
                    {
                        if (String.Compare(var, directoryName, StringComparison.OrdinalIgnoreCase) == 0)
                        {
                            string[] fileNames = isoStorage.GetFileNames(searchPattern);

                            if (fileNames == null || fileNames.Length == 0)
                            {
                                return list.ToArray();
                            } // if
                            else
                            {
                                foreach (string var2 in fileNames)
                                {
                                    list.Add(var2);
                                }
                            }
                        }
                    }
                }
            };

            return list.ToArray();
        }


        /// <summary>
        /// Get Whether specified directory exists
        /// </summary>
        /// <param name="directoryName">Name of the directory.</param>
        /// <returns>true if directory exists else false</returns>
        public virtual bool DirectoryExists(string directoryName)
        {
            if (String.IsNullOrEmpty(directoryName))
            {
                return false;
            } // if

            using (IsolatedStorageFile isoStorage = this.GetIsolatedStorage())
            {
                string[] storeNames = isoStorage.GetDirectoryNames(directoryName);

                if (storeNames == null || storeNames.Length == 0)
                {
                    return false;
                } // if
                else
                {
                    foreach (string var in storeNames)
                    {
                        if (String.Compare(var, directoryName, StringComparison.OrdinalIgnoreCase) == 0)
                        {
                            return true;
                        }
                    }
                }
            }

            return false;

        }


        /// <summary>
        /// Get The Name of Storage used by the Provider
        /// </summary>
        /// <value>storage name.</value>
        public virtual string Name
        {
            get
            {
                return "Isolated";
            }
        }

        /// <summary>
        /// load the file to StringSTream
        /// </summary>
        /// <param name="file">The file.</param>
        /// <returns>MemoryStream containing the loaded file</returns>
        public virtual StringStream Load(string file)
        {
            using (IsolatedStorageFile isoStorage = this.GetIsolatedStorage())
            {

                string[] storeNames = isoStorage.GetFileNames(file);

                if (storeNames == null || storeNames.Length == 0)
                {
                    return null;
                } // if
                using (IsolatedStorageFileStream reader = new IsolatedStorageFileStream(file, FileMode.Open, isoStorage))
                {
                    byte[] contents = new byte[reader.Length];
                    reader.Read(contents, 0, (int)reader.Length);
                    return new StringStream(contents);
                } // using
            } // using
        }

        /// <summary>
        /// Saves the specified configuration.
        /// </summary>
        /// <param name="file">The file name to save.</param>
        /// <param name="contents">The contents.</param>
        public virtual void Save(string file, StringStream contents)
        {
            if (String.IsNullOrEmpty(file))
            {
                throw new ArgumentNullException("file");
            }

            if (contents == null)
            {
                throw new ArgumentNullException("contents");
            }

            using (IsolatedStorageFile isoStorage = this.GetIsolatedStorage())
            {
                using (IsolatedStorageFileStream writer = new IsolatedStorageFileStream(file, FileMode.Create, isoStorage))
                {
                    byte[] data = contents.ToArray();
                    writer.Write(data, 0, data.Length);
                } // using
            } // using
        }


        /// <summary>
        /// Creates the directory.
        /// </summary>
        /// <param name="directory">The path of the directory to create.</param>
        public void CreateDirectory(string directory)
        {
            if (String.IsNullOrEmpty(directory))
            {
                throw new ArgumentNullException("directory");
            } // if

            using (IsolatedStorageFile isoStorage = this.GetIsolatedStorage())
            {
                string[] storeNames = isoStorage.GetDirectoryNames(directory);

                if (storeNames == null || storeNames.Length == 0)
                {
                    isoStorage.CreateDirectory(directory);
                } // if

            }

        }


        /// <summary>
        /// Deletes the File.
        /// </summary>
        /// <param name="fileName">Name of the file.</param>
        public virtual void DeleteFile(string fileName)
        {
            if (String.IsNullOrEmpty(fileName))
            {
                throw new ArgumentNullException("fileName");
            } // if

            try
            {

                using (IsolatedStorageFile isoFile = this.GetIsolatedStorage())
                {
                    isoFile.DeleteFile(fileName);

                } // using
            } // try
            catch (ArgumentException) { } // catch
            catch (SecurityException) { } // catch
            catch (IsolatedStorageException) { } // catch
        }

        /// <summary>
        /// Deletes the directory.
        /// </summary>
        /// <param name="directory">The directory.</param>
        public void DeleteDirectory(string directory)
        {
            if (String.IsNullOrEmpty(directory))
            {
                throw new ArgumentNullException("directory");
            } // if

            try
            {

                using (IsolatedStorageFile isoFile = this.GetIsolatedStorage())
                {

                    string[] dirNames = isoFile.GetDirectoryNames("*");
                    string[] fileNames = isoFile.GetFileNames(directory + "\\*");

                    // Delete all the files currently in the Archive directory.

                    if (fileNames.Length > 0)
                    {
                        for (int i = 0; i < fileNames.Length; ++i)
                        {
                            string temp = directory + "\\" + fileNames[i];
                            // Delete the files.
                            isoFile.DeleteFile(temp);
                        } // for
                    } // if


                    if (dirNames.Length > 0)
                    {
                        for (int i = 0; i < dirNames.Length; ++i)
                        {
                            // Delete the Archive directory.
                            isoFile.DeleteDirectory(directory);
                        } // for
                    } // if

                } // using
            } // try
            catch(ArgumentException) { } // catch
            catch (SecurityException) { } // catch
            catch (IsolatedStorageException) { } // catch
        }
        #endregion

    }
}
